{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "8577012d",
      "metadata": {},
      "source": [
        "# 🤖 Microsoft Agent Framework\n",
        "\n",
        "## ⚠️ Why Not Autogen?\n",
        "\n",
        "**Autogen is now a dead end for the future.** (September 2025)\n",
        "\n",
        "- Microsoft officially put **Autogen into maintenance mode** — no new features will be added.\n",
        "- All new development, innovation, features, and support go to **Agent Framework**.\n",
        "- Enterprises are migrating to Agent Framework.\n",
        "- If you learn Autogen deeply now, you’ll be learning a deprecated ecosystem.\n",
        "\n",
        "## 📚 Main Concepts\n",
        "\n",
        "**Microsoft Agent Framework** consists of these core components:\n",
        "\n",
        "- **🤖 Agents** - AI entities that can reason, use tools, and communicate\n",
        "- **🔄 Workflows** - Data-flow graphs that orchestrate agents and tasks with explicit control\n",
        "- **💬 Messages** - How agents communicate (typed and routed through specific paths)\n",
        "- **🔌 Model Clients** - Connect to LLMs (OpenAI, Azure, etc.)\n",
        "- **🛠️ Tools** - Functions agents can call (web search, code execution, APIs)\n",
        "- **💾 State Management** - Thread-based system for conversation history and context\n",
        "- **💾 Checkpointing** - Save and resume long-running workflows\n",
        "\n",
        "Microsoft Agent Framework's LLM calls are **asynchronous** (non-blocking), so they use async/await to allow your program to do other things while waiting for the LLM response instead of freezing.\n",
        "\n",
        "---\n",
        "📢 Discover more Agentic AI notebooks on my [GitHub repository](https://github.com/lisekarimi/agentverse) and explore additional AI projects on my [portfolio](https://lisekarimi.com)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "faa71565",
      "metadata": {},
      "outputs": [],
      "source": [
        "# uv add agent-framework --pre"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "9e96cb76",
      "metadata": {},
      "outputs": [],
      "source": [
        "import asyncio\n",
        "import gradio as gr\n",
        "import os\n",
        "from dotenv import load_dotenv\n",
        "from agent_framework.openai import OpenAIChatClient\n",
        "from typing import Annotated\n",
        "import requests\n",
        "from agent_framework import (ChatAgent, ChatMessageStore)\n",
        "from pydantic import Field"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "097e9a37",
      "metadata": {},
      "outputs": [],
      "source": [
        "load_dotenv(override=True)\n",
        "MODEL_ID = \"gpt-4o-mini\"\n",
        "pushover_user = os.getenv(\"PUSHOVER_USER\")\n",
        "pushover_token = os.getenv(\"PUSHOVER_TOKEN\")\n",
        "\n",
        "# Validate required environment variables\n",
        "if not pushover_user or not pushover_token:\n",
        "    print(\"Warning: PUSHOVER_USER and PUSHOVER_TOKEN are required. Please set them in your .env file.\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "d01f7953",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Define the Pushover tool\n",
        "def send_pushover_notification(\n",
        "    message: Annotated[str, Field(description=\"The message to send\")],\n",
        "    title: Annotated[str, Field(description=\"The notification title\")] = \"Agent Alert\"\n",
        ") -> str:\n",
        "    \"\"\"Send a push notification via Pushover.\"\"\"\n",
        "\n",
        "    response = requests.post(\n",
        "        \"https://api.pushover.net/1/messages.json\",\n",
        "        data={\n",
        "            \"token\": pushover_token,\n",
        "            \"user\": pushover_user,\n",
        "            \"message\": message,\n",
        "            \"title\": title\n",
        "        }\n",
        "    )\n",
        "\n",
        "    return \"✅ Notification sent\" if response.status_code == 200 else \"❌ Failed\""
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b87fc94a",
      "metadata": {},
      "source": [
        "## Simple Agent with tool"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "9f3b5889",
      "metadata": {},
      "outputs": [],
      "source": [
        "async def main():\n",
        "    agent = ChatAgent(\n",
        "        chat_client=OpenAIChatClient(model_id=MODEL_ID),\n",
        "        instructions=\"You are a helpful assistant that can send push notifications via Pushover.\",\n",
        "        tools=[send_pushover_notification]\n",
        "    )\n",
        "\n",
        "    print(\"=== Test 1: Simple Question ===\")\n",
        "    result = await agent.run(\"What is 5 + 3?\")\n",
        "    print(result.text)\n",
        "    print()\n",
        "\n",
        "    print(\"=== Test 2: Send Notification ===\")\n",
        "    result = await agent.run(\"Send me a notification saying 'Hello from Microsoft Agent Framework!'\")\n",
        "    print(result.text)\n",
        "\n",
        "# For Jupyter\n",
        "await main()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b77842e2",
      "metadata": {},
      "source": [
        "## Agent with tool and memory"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "69ae5753",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Create message store for memory\n",
        "message_store = ChatMessageStore()\n",
        "\n",
        "# Create agent with memory (thread-based)\n",
        "agent = ChatAgent(\n",
        "    chat_client=OpenAIChatClient(model_id=MODEL_ID),\n",
        "    instructions=\"You are a helpful assistant. Use the pushover tool when user asks to send notifications.\",\n",
        "    tools=[send_pushover_notification],\n",
        "    chat_message_store_factory=lambda: message_store\n",
        ")\n",
        "\n",
        "# Chat function with memory\n",
        "async def chat_async(message, history):\n",
        "    # Run agent with thread_id for memory\n",
        "    result = await agent.run(message, thread_id=\"user_1\")\n",
        "    return result.text\n",
        "\n",
        "# Wrapper for Gradio (Gradio doesn't support async directly)\n",
        "def chat(message, history):\n",
        "    return asyncio.run(chat_async(message, history))\n",
        "\n",
        "# Launch Gradio\n",
        "demo = gr.ChatInterface(\n",
        "    chat,\n",
        "    title=\"Microsoft Agent Framework Chatbot\",\n",
        "    description=\"Chat with memory + Pushover notifications\",\n",
        ")\n",
        "\n",
        "demo.launch()"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": ".venv",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.12.11"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}
